package com.teamtwoseven.todo;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;

/**
 * This screen allows the user to do a custom search of their items.
 * 
 * @author teamtwoseven
 */
public class ItemSearch extends Activity implements OnClickListener {

	private static final int DATE_DIALOG_ID = 0;
	private static final int TIME_DIALOG_ID = 1;
	
	private long userRowID;
	private Storage storage;
	private Button bLogout, bSettings, bLocation, bSearch, bCancel;
	private Button bSetDate0, bSetDate1, bSetTime0, bSetTime1;
	private EditText etSearchName;
	private RadioButton rbBefore, rbAfter, rbBetween;
	private Spinner spinner;
	private CheckBox cbDate, cbName, cbCategory, cbLocation;
	private int indicator;
	
	private DatePickerDialog.OnDateSetListener mDateSetListener;
	private TimePickerDialog.OnTimeSetListener mTimeSetListener;
	

	/**
	 * Called when the activity is first created.
	 * 
	 * @param savedInstanceState
	 * 			allows instance data to be stored
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.search);

		getUser(); // sets userRowID, storage, and the welcome text

		bLogout = (Button) findViewById(R.id.search_bLogout);
		bLogout.setOnClickListener(this);
		bSettings = (Button) findViewById(R.id.search_bSettings);
		bSettings.setOnClickListener(this);
		bLocation = (Button) findViewById(R.id.search_bLocation);
		bLocation.setOnClickListener(this);
		bSearch = (Button) findViewById(R.id.search_bSearch);
		bSearch.setOnClickListener(this);
		bCancel = (Button) findViewById(R.id.search_bCancel);
		bCancel.setOnClickListener(this);
		bSetDate0 = (Button) findViewById(R.id.search_bSetDate0);
		bSetDate0.setOnClickListener(this);
		bSetDate1 = (Button) findViewById(R.id.search_bSetDate1);
		bSetDate1.setOnClickListener(this);
		bSetTime0 = (Button) findViewById(R.id.search_bSetTime0);
		bSetTime0.setOnClickListener(this);
		bSetTime1 = (Button) findViewById(R.id.search_bSetTime1);
		bSetTime1.setOnClickListener(this);

		bSetDate0.setEnabled(false);
		bSetTime0.setEnabled(false);
		bSetDate1.setEnabled(false);
		bSetTime1.setEnabled(false);
		bLocation.setEnabled(false);

		etSearchName = (EditText) findViewById(R.id.search_etItemName);
		etSearchName.setEnabled(false);
		etSearchName.setClickable(false);
		etSearchName.setFocusable(false);

		rbBefore = (RadioButton) findViewById(R.id.search_rbBeforeDate);
		rbAfter = (RadioButton) findViewById(R.id.search_rbAfterDate);
		rbBetween = (RadioButton) findViewById(R.id.search_rbBetweenDates);

		rbBefore.setChecked(true);
		rbBefore.setEnabled(false);
		rbAfter.setEnabled(false);
		rbBetween.setEnabled(false);

		RadioGroup rgDateOption =
			(RadioGroup) findViewById(R.id.search_rgDateGroup);
		rgDateOption.setOnCheckedChangeListener(
			new RadioGroup.OnCheckedChangeListener() {
				public void onCheckedChanged(RadioGroup group, int checkedId) {
					boolean checked = rbBetween.isChecked();
					bSetDate1.setEnabled(checked);
					bSetTime1.setEnabled(checked);
				}
			});

		cbDate = (CheckBox) findViewById(R.id.search_cbDate);
		cbDate.setOnClickListener(this);
		cbName = (CheckBox) findViewById(R.id.search_cbItemName);
		cbName.setOnClickListener(this);
		cbLocation = (CheckBox) findViewById(R.id.search_cbLocation);
		cbLocation.setOnClickListener(this);
		cbCategory = (CheckBox) findViewById(R.id.search_cbCategory);
		cbCategory.setOnClickListener(this);

		spinner = (Spinner) findViewById(R.id.search_spinner);
		ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
			this, R.array.category_type,
			android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(
			android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);
		spinner.setEnabled(false);
		
		mDateSetListener = new DatePickerDialog.OnDateSetListener() {
			// called when date is set by the user
			public void onDateSet(DatePicker view, int year, int month,
				int day) {
				String dateHolder = (month + 1) + "/" + day + "/" + year;
				
				if (indicator == 1) {
					bSetDate0.setText(dateHolder);
				} else {
					bSetDate1.setText(dateHolder);
				}
			}
		};
		
		mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
			// called when time is set by the user
			public void onTimeSet(TimePicker view, int hour, int minute) {
				String middle = ":", ending, timeHolder;
				
				if (minute < 10) {
					middle += "0";
				}
				if (hour > 12) {
					hour = hour - 12;
					ending = "pm";
				}
				else if (hour == 12) {
					ending = "pm";
				}
				else {
					if (hour == 0) {
						hour = 12;
					}
					ending = "am";
				}

				timeHolder = hour + middle + minute + ending;

				if (indicator == 1) {
					bSetTime0.setText(timeHolder);
				}
				else {
					bSetTime1.setText(timeHolder);
				}
			}
		};
	}

	/**
	 * Handles button clicks
	 * 
	 * @param arg0
	 * 			the element that was clicked
	 */
	public void onClick(View arg0) {
		if (arg0 == bSearch) {
			if (verify() && search()) {
				// search returns true if items matching the search criteria
				// were found
				finish();
			}
		}
		else if (arg0 == bCancel) {
			// Have the list in Main show all items and the spinner say
			// "All Items" rather than "Custom Search" by setting Main.items
			// to null (Main.updateList() will handle it from here)
			Main.items = null;
			finish();
		}
		else if (arg0 == bSettings) {
			// End this activity; Main will launch the settings screen, then if
			// the user returns to Main have the list show all items and the
			// spinner say "All Items" rather than "Custom Search" by setting
			// Main.items to null (Main.updateList() will handle it from here)
			Main.items = null;
			setResult(2);
			finish();
		}
		else if (arg0 == bLogout) {
			// End this activity; Main will launch the login screen
			setResult(1);
			finish();
		}
		else if (arg0 == bSetDate0) {
			indicator = 1;
			showDialog(DATE_DIALOG_ID);
		}
		else if (arg0 == bSetTime0) {
			indicator = 1;
			showDialog(TIME_DIALOG_ID);
		}
		else if (arg0 == bSetDate1) {
			indicator = 2;
			showDialog(DATE_DIALOG_ID);
		}
		else if (arg0 == bSetTime1) {
			indicator = 2;
			showDialog(TIME_DIALOG_ID);
		}
		else if (arg0 == cbDate) {
			boolean dateChecked = cbDate.isChecked();
			boolean betweenChecked = rbBetween.isChecked();
			
			rbBefore.setEnabled(dateChecked);
			rbAfter.setEnabled(dateChecked);
			rbBetween.setEnabled(dateChecked);
			bSetDate0.setEnabled(dateChecked);
			bSetTime0.setEnabled(dateChecked);
			rbBetween.requestFocus();
			rbBefore.setSelected(dateChecked);
			bSetDate1.setEnabled(betweenChecked && dateChecked);
			bSetTime1.setEnabled(betweenChecked && dateChecked);
		}
		else if (arg0 == cbName) {
			boolean checked = cbName.isChecked();
			
			etSearchName.setEnabled(checked);
			etSearchName.setClickable(checked);
			etSearchName.setFocusable(checked);
			etSearchName.setFocusableInTouchMode(checked);
			etSearchName.requestFocus();
		}
		else if (arg0 == cbLocation) {
			bLocation.setEnabled(cbLocation.isChecked());
			bLocation.requestFocus();
		}
		else if (arg0 == cbCategory) {
			spinner.setEnabled(cbCategory.isChecked());
			spinner.requestFocus();
		}
	}

	/**
	 * Verifies the search criteria is valid. If not, displays a dialog listing
	 * why.
	 * 
	 * @return true if the search criteria is valid, false otherwise
	 */
	private boolean verify() {
		boolean success = true;
		String feedback = "";

		if (cbDate.isChecked()) {
			if (rbBefore.isChecked() || rbAfter.isChecked()) {
				if (bSetDate0.getText().toString().equals("Set Date")) {
					feedback += "Set a date\n";
					success = false;
				}
				if (bSetTime0.getText().toString().equals("Set Time")) {
					feedback += "Set a time\n";
					success = false;
				}
			}
			else {
				if (bSetDate0.getText().toString().equals("Set Date")) {
					feedback += "Set a start date\n";
					success = false;
				}
				if (bSetDate1.getText().toString().equals("Set Date")) {
					feedback += "Set an end date\n";
					success = false;
				}
				if (bSetTime0.getText().toString().equals("Set Time")) {
					feedback += "Set a time for the start date\n";
					success = false;
				}
				if (bSetTime1.getText().toString().equals("Set Time")) {
					feedback += "Set a time for the end date\n";
					success = false;
				}
			}
		}
		if (cbName.isChecked()) {
			String text = etSearchName.getText().toString();
			
			if ((text == null) || (text.replaceAll("\\s+", "").equals(""))) {
				feedback += "Enter a name for this item\n";
				success = false;
			}
		}
		if (cbLocation.isChecked()) {
			feedback += "Locations are not yet supported";
			success = false;
		}
		else if (!cbDate.isChecked() && !cbName.isChecked() &&
			!cbCategory.isChecked() && !cbLocation.isChecked()) {
			
			feedback += "Select search criteria";
			success = false;
		}
		if (!success) {
			// Tell the user nothing was found
			popupDialog(feedback, false);
		}
		return success;
	}

	/**
	 * Searches the database for items matching the given search criteria.
	 * 
	 * @return true if matching items were found, false if not
	 */
	private boolean search() {
		boolean itemsFound = false;
		String sqlWhere = "", recurring = "";
		Item[] items, recurringItems = new Item[0];
		LinkedList<Item> returnItems;
		
		if (cbDate.isChecked()) {
			String operator;
			long deadline0 = 0;
			
			if (rbBefore.isChecked()) {
				operator = " < ";
			}
			else {
				operator = " > ";
			}
			try {
				deadline0 = new SimpleDateFormat("MM/dd/yyyy'T'hh:mma").parse(
					bSetDate0.getText() + "T" + bSetTime0.getText()).getTime();
				sqlWhere += Storage.I_KEY_DEADLINE + operator +
					deadline0;
			} catch (ParseException e) {
				e.printStackTrace();
			}
			if (operator.equals(" > ")) {
				// Get all recurring items
				recurring += Storage.I_KEY_FREQUENCY + "<>'Once'";
				recurringItems =
					storage.getSpecificItems(userRowID, recurring);
				
				// Remove all recurring items after the given deadline
				for (int i = 0; i < recurringItems.length; i++) {
					if (recurringItems[i].getDeadline() > deadline0) {
						recurringItems[i] = null;
					}
				}
			}
			if (rbBetween.isChecked()) {
				long deadline1;
				try {
					deadline1 = new SimpleDateFormat(
						"MM/dd/yyyy'T'hh:mma").parse(bSetDate1.getText() +
						"T" + bSetTime1.getText()).getTime();
					sqlWhere += " AND " + Storage.I_KEY_DEADLINE + " < " +
						deadline1;
				} catch (ParseException e) {
					e.printStackTrace();
				}
				
			}
		}
		if (cbName.isChecked()) {
			String itemName = etSearchName.getText().toString();
			
			if (sqlWhere.equals("")) {
				sqlWhere += Storage.I_KEY_NAME + "='" + itemName + "'";
			}
			else {
				sqlWhere += " AND " + Storage.I_KEY_NAME + "='" +
					itemName + "'";
			}
		}
		if (cbCategory.isChecked()) {
			String category = spinner.getSelectedItem().toString();
			if (sqlWhere.equals("")) {
				sqlWhere += Storage.I_KEY_CATEGORY + "='" + category + "'";
			}
			else {
				sqlWhere += " AND " + Storage.I_KEY_CATEGORY + "='" +
					category + "'";
			}
		}
		if (cbLocation.isChecked()) {
			// Add location services later
		}

		items = storage.getSpecificItems(userRowID, sqlWhere);
		returnItems = new LinkedList<Item>();
		
		// Add all recurring items that have deadlines outside the chosen range
		// but occur within it to returnItems
		for (int i = 0; i < recurringItems.length; i++) {
			if (recurringItems[i] != null) {
				returnItems.add(recurringItems[i]);
			}
		}
		
		// Add all items in items[] to returnItems
		for (int i = 0; i < items.length; i++) {
			returnItems.add(items[i]);
		}
		
		if (returnItems.size() > 0) {
			Main.items = returnItems.toArray(items);
			itemsFound = true;
		}
		else {
			popupDialog(
				"No items were found that match your search criteria.", false);
		}
		return itemsFound;
	}
	
	/**
	 * Displays a dialog listing the given message and an OK button. If done is
	 * true, clicking OK ends this Activity. Otherwise OK closes the dialog.
	 * 
	 * @param message
	 * 			text to display to the user
	 * @param done
	 * 			if true, clicking OK finishes the Activity; if false, OK just
	 * 			closes the dialog
	 */
	private void popupDialog(String message, final boolean done) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);

		builder.setMessage(message);
		builder.setCancelable(false);
		builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int id) {
				dialog.cancel();
				if (done) {
					finish();
				}
			}
		});
		builder.show();
	}

	protected Dialog onCreateDialog(int id) {
		Calendar c = Calendar.getInstance();
		switch (id) {
		case DATE_DIALOG_ID:
			return new DatePickerDialog(this, mDateSetListener,
				c.get(Calendar.YEAR), c.get(Calendar.MONTH),
				c.get(Calendar.DAY_OF_MONTH));
		case TIME_DIALOG_ID:
			return new TimePickerDialog(this, mTimeSetListener,
					(c.get(Calendar.HOUR_OF_DAY)+21)%24,
					(c.get(Calendar.MINUTE)+30)%60, false);
		}
		return null;
	}

	/**
	 * Gets the row ID of the current user's stored info. Also sets the welcome
	 * text to display the user's full name if it is less than 22 characters;
	 * up to 22 characters of the user's first name otherwise.
	 */
	private void getUser() {
		userRowID = Singleton.getInstance().getUserRowID();
		storage = new Storage(ItemSearch.this);
		
		String name = storage.getFullName(userRowID);

		if (name.length() > 22) {
			name = name.substring(0, 22);
			if (name.substring(1, 21).contains(" ")) {
				name = name.substring(0, name.indexOf(" "));
			}
		}

		TextView tvWelcome = (TextView) findViewById(R.id.search_tvWelcome);
		tvWelcome.setText("Welcome, " + name + "!");
	}
}
